#include "thread.h"
#include <stdio.h>
#include <assert.h>
#include <pthread.h>

thread_mutex_t * mutexadd=NULL;


static void * thread_print_tata(void * arg){
  int i;
  int j;
  for(i=0;i<300;i++){
    for(j=0;j<700000;j++);
    printf("%i Tata\n",i);
  }
  thread_exit(arg);
}

static void * thread_print_toto(void * arg){
  int i;
  int j;
  for(i=0;i<300;i++){
    for(j=0;j<700000;j++);
    printf("%i Toto\n",i);
  }
  thread_exit(arg);
}

static void * thread_print_titi(void * arg){
  int i;
  int j;
  for(i=0;i<400;i++){
    for(j=0;j<700000;j++);
    printf("%i Titi\n",i);
  }
  thread_exit(arg);
}

static void * threadfunc(void * arg){
  char *name = arg;
  printq();
  printf("je suis le thread %p, lancé avec l'argument %s\n",
	 thread_self(), name);
  thread_yield();
  printq();
  printf("je suis encore le thread %p, lancé avec l'argument %s\n",
	 thread_self(), name);
  thread_exit(arg);
}

static void * thread_test(void * arg){
  int i;
  i++;
  thread_exit(arg);
}

static void * pthread_test(void * arg){
  int i;
  i++;
  pthread_exit(arg);
}


static void * thread_add(void * arg){
  int i;
  for (i=0;i<10000;i++){
    (*(int*)arg)++;
    thread_yield();
  }
  printf("Nouvelle valeur calculé sans mutex par add :%i\n",*(int*)arg);
  thread_exit(arg);
}

static void * thread_dec(void * arg){
  int i;
  for (i=0;i<5000;i++){
    (*(int*)arg)--;
    thread_yield();
  }
  printf("Nouvelle valeur calculé sans mutex par dec :%i\n",*(int*)arg);
  thread_exit(arg);
}

static void * thread_add_mutex(void * arg){
  int i;
  thread_mutex_lock(mutexadd);
  for (i=0;i<10000;i++){
    (*(int*)arg)++;
    thread_yield();
  }
  printf("Nouvelle valeur calculé avec mutex par add :%i\n",*(int*)arg);
  thread_mutex_unlock(mutexadd);
  thread_exit(arg);
}

static void * thread_dec_mutex(void * arg){
  int i;
  thread_mutex_lock(mutexadd);
  for (i=0;i<5000;i++){
    (*(int*)arg)--;
    thread_yield();
  }
  printf("Nouvelle valeur calculé avec mutex par dec :%i\n",*(int*)arg);
  thread_mutex_unlock(mutexadd);
  thread_exit(arg);
}

int main(int argc, char *argv[]){
  thread_t thread1, thread2, thread3;
  void *retval1, *retval2,*retval3;
  int err;
 
  printf("le main lance 2 threads...\n");
  printq();
  err = thread_create(&thread1, threadfunc, "thread1");
  assert(!err);
  printq();
  err = thread_create(&thread2, threadfunc, "thread2");
  assert(!err);
  printf("le main a lancé les threads %p et %p\n",
	 thread1, thread2);
  printq();
  printf("le main attend les threads\n");
  err = thread_join(thread1, &retval1);
  assert(!err);
  printq();
  err = thread_join(thread2, &retval2);
  assert(!err);
  printq();
  printf("les threads ont terminé en renvoyant '%s' and '%s'\n", (char *) retval1, (char *) retval2);

/*
//Lance argv[1] fois un thread et l'attend 
//Permet de tester l'utilisation memoire
  if(argc<1) return EXIT_FAILURE;
  pthread_t pthread1;
  printf("\n");
  int i=0;
 
  for(i=0; i<atoi(argv[1]);i++)
    {
      err=thread_create(&thread1,thread_test,"test");
      assert(!err);
      err=thread_join(thread1,&retval1);
      assert(!err);
      }
  printf("On a lancé %i fois un thread et on l'a attendu\n",atoi(argv[1]));
  printf("\n");
  
  //Test sur les mutex
  int j=0;
  thread_t add,dec;
  void * addret, *decret;
  err=thread_create(&add,thread_add,(void*)&j);
  assert(!err);
  err=thread_create(&dec,thread_dec,(void*)&j);
  assert(!err);
  err=thread_join(add,&addret);
  assert(!err);
  err=thread_join(dec,&decret);
  assert(!err);
  j=0;
  err=thread_mutex_init(&mutexadd);
  assert(!err);
  err=thread_create(&add,thread_add_mutex,(void*)&j);
  assert(!err); 
  err=thread_create(&dec,thread_dec_mutex,(void*)&j);
  assert(!err);
  err=thread_join(add,&addret);
  assert(!err);
  err=thread_join(dec,&decret);
  assert(!err);
  err=thread_mutex_destroy(mutexadd);
  assert(!err);
  
  //Test sur la préemption
  
  err = thread_create(&thread1, thread_print_tata,NULL);
  assert(!err);
  err = thread_create(&thread2, thread_print_titi,NULL);
  assert(!err);
  err = thread_create(&thread3, thread_print_toto,NULL);
  assert(!err);
  err = thread_join(thread1, &retval1);
  assert(!err);
  err = thread_join(thread2, &retval2);
  assert(!err);
  err = thread_join(thread3, &retval3);
  assert(!err);

  main_free(); //permet de tester la liberation des ressource du thread du main
*/
  return EXIT_SUCCESS;
}
